package com.cancan.cloud.shop.filter;

import com.cancan.cloud.shop.utils.BuilderHeader;
import com.cancan.cloud.shop.utils.LogBaseContractValue;
import com.cancan.cloud.shop.utils.LogIdManagement;
import com.cancan.cloud.shop.utils.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

/**
 * @author ZhouFufeng
 * @since 2020/4/10
 **/
@Slf4j
public abstract class BaseGlobalFilter implements GlobalFilter, Ordered {

    @Value("${regex.static:}")
    private String regs;

    /**
     * 判断请求静态资源
     */
    public boolean isStatic(ServerWebExchange exchange) {
        boolean hasReleased = (boolean) exchange.getAttributes().getOrDefault("hasReleased",false);
        if (!hasReleased) {
            List<String> list;

            if (StringUtils.isEmpty(regs)) {
                return false;
            }
            list = Arrays.asList(regs.split(","));

            String path = exchange.getRequest().getURI().getPath();
            if (path.endsWith("/")) {
                //如果以/结尾的，当作静态资源处理
                return true;
            }
            for (String s : list) {
                if (Pattern.compile(s).matcher(path).find()) {
                    log.info("静态资源请求已放行，IP:"+getIpAddress(exchange.getRequest())+"URL为:" + path);
                    exchange.getAttributes().put("hasReleased", true);
                    return true;
                }
            }
            return false;
        }
        return true;

    }
    public static String getIpAddress(ServerHttpRequest request) {
        HttpHeaders headers = request.getHeaders();
        String ip = headers.getFirst("x-forwarded-for");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个ip值，第一个ip才是真实ip
            if (ip.contains(",")) {
                ip = ip.split(",")[0];
            }
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddress().getAddress().getHostAddress();
        }
        return ip;
    }

    @Override
    public final Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //获取全局id
        String globalId = exchange.getRequest().getHeaders().getFirst(LogBaseContractValue.KEY_OF_ID);
        LogIdManagement logIdManagement = SpringUtils.getApplicationContext().getBean(LogIdManagement.class);
        if (StringUtils.isEmpty(globalId)) {
            globalId = logIdManagement.create();
            ServerHttpRequest request = BuilderHeader.addHeader(exchange, LogBaseContractValue.KEY_OF_ID, globalId);
            exchange = exchange.mutate().request(request).build();
        }
        logIdManagement.setId(globalId);
        if (isStatic(exchange)) {
            return chain.filter(exchange);
        }
        //当资源不放行的时候，重新执行下一个执行器
        return this.doFilter(exchange, chain);
    }

    public abstract Mono<Void> doFilter(ServerWebExchange exchange, GatewayFilterChain chain);

}
